from django.utils import timezone
from datetime import datetime, timedelta
from .models import LeaveApplication, UserProfile
import calendar


class LeaveStatistics:
    """请假统计工具"""
    
    @staticmethod
    def get_user_leave_summary(user, year=None):
        """获取用户请假汇总"""
        if year is None:
            year = timezone.now().year
        
        start_date = datetime(year, 1, 1).date()
        end_date = datetime(year, 12, 31).date()
        
        applications = LeaveApplication.objects.filter(
            applicant=user,
            start_date__gte=start_date,
            end_date__lte=end_date,
            status='approved'
        )
        
        summary = {}
        total_days = 0
        
        for app in applications:
            leave_type = app.leave_type.name
            if leave_type not in summary:
                summary[leave_type] = {
                    'count': 0,
                    'days': 0,
                    'applications': []
                }
            
            summary[leave_type]['count'] += 1
            summary[leave_type]['days'] += app.days_requested
            summary[leave_type]['applications'].append(app)
            total_days += app.days_requested
        
        return {
            'year': year,
            'total_days': total_days,
            'by_type': summary,
            'total_applications': applications.count()
        }
    
    @staticmethod
    def get_department_leave_summary(department, year=None):
        """获取部门请假汇总"""
        if year is None:
            year = timezone.now().year
        
        start_date = datetime(year, 1, 1).date()
        end_date = datetime(year, 12, 31).date()
        
        # 获取部门所有用户
        users = UserProfile.objects.filter(department=department).values_list('user', flat=True)
        
        applications = LeaveApplication.objects.filter(
            applicant__in=users,
            start_date__gte=start_date,
            end_date__lte=end_date,
            status='approved'
        )
        
        summary = {
            'department': department.name,
            'year': year,
            'total_applications': applications.count(),
            'total_days': sum(app.days_requested for app in applications),
            'by_user': {},
            'by_type': {}
        }
        
        # 按用户统计
        for app in applications:
            user_name = app.applicant.get_full_name() or app.applicant.username
            if user_name not in summary['by_user']:
                summary['by_user'][user_name] = {
                    'count': 0,
                    'days': 0
                }
            summary['by_user'][user_name]['count'] += 1
            summary['by_user'][user_name]['days'] += app.days_requested
        
        # 按类型统计
        for app in applications:
            leave_type = app.leave_type.name
            if leave_type not in summary['by_type']:
                summary['by_type'][leave_type] = {
                    'count': 0,
                    'days': 0
                }
            summary['by_type'][leave_type]['count'] += 1
            summary['by_type'][leave_type]['days'] += app.days_requested
        
        return summary
    
    @staticmethod
    def get_monthly_leave_trend(year=None):
        """获取月度请假趋势"""
        if year is None:
            year = timezone.now().year
        
        monthly_data = []
        
        for month in range(1, 13):
            start_date = datetime(year, month, 1).date()
            end_date = datetime(year, month, calendar.monthrange(year, month)[1]).date()
            
            applications = LeaveApplication.objects.filter(
                start_date__gte=start_date,
                start_date__lte=end_date,
                status='approved'
            )
            
            monthly_data.append({
                'month': month,
                'month_name': calendar.month_name[month],
                'applications': applications.count(),
                'total_days': sum(app.days_requested for app in applications)
            })
        
        return monthly_data


class WorkdayCalculator:
    """工作日计算工具"""
    
    @staticmethod
    def calculate_workdays(start_date, end_date, exclude_weekends=True):
        """计算工作日天数"""
        if start_date > end_date:
            return 0
        
        current_date = start_date
        workdays = 0
        
        while current_date <= end_date:
            if exclude_weekends:
                # 排除周末 (0=Monday, 6=Sunday)
                if current_date.weekday() < 5:
                    workdays += 1
            else:
                workdays += 1
            current_date += timedelta(days=1)
        
        return workdays
    
    @staticmethod
    def is_workday(date, exclude_weekends=True):
        """判断是否为工作日"""
        if exclude_weekends and date.weekday() >= 5:
            return False
        return True
    
    @staticmethod
    def get_next_workday(date, exclude_weekends=True):
        """获取下一个工作日"""
        next_date = date + timedelta(days=1)
        while not WorkdayCalculator.is_workday(next_date, exclude_weekends):
            next_date += timedelta(days=1)
        return next_date


class LeaveValidator:
    """请假申请验证工具"""
    
    @staticmethod
    def validate_leave_dates(start_date, end_date):
        """验证请假日期"""
        errors = []
        
        if start_date > end_date:
            errors.append('开始日期不能晚于结束日期')
        
        if start_date < timezone.now().date():
            errors.append('开始日期不能早于今天')
        
        # 检查是否跨年
        if start_date.year != end_date.year:
            errors.append('请假时间不能跨年')
        
        return errors
    
    @staticmethod
    def validate_leave_overlap(user, start_date, end_date, exclude_application_id=None):
        """验证请假时间是否重叠"""
        overlapping_applications = LeaveApplication.objects.filter(
            applicant=user,
            status__in=['submitted', 'supervisor_approved', 'approved'],
            start_date__lte=end_date,
            end_date__gte=start_date
        )
        
        if exclude_application_id:
            overlapping_applications = overlapping_applications.exclude(id=exclude_application_id)
        
        if overlapping_applications.exists():
            return ['请假时间与已有申请重叠']
        
        return []
    
    @staticmethod
    def validate_advance_notice(start_date, leave_type, days_requested):
        """验证提前通知时间"""
        errors = []
        days_until_leave = (start_date - timezone.now().date()).days
        
        # 根据请假天数要求不同的提前通知时间
        if days_requested >= 7:
            required_notice = 7  # 7天以上请假需要提前7天申请
        elif days_requested >= 3:
            required_notice = 3  # 3-6天请假需要提前3天申请
        else:
            required_notice = 1  # 1-2天请假需要提前1天申请
        
        if days_until_leave < required_notice:
            errors.append(f'请假{days_requested}天需要提前{required_notice}天申请')
        
        return errors
